<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebRTC视频通话</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        
        .video-container {
            display: flex;
            justify-content: space-around;
            margin: 20px 0;
            flex-wrap: wrap;
        }
        
        .video-wrapper {
            position: relative;
            width: 45%;
            margin-bottom: 20px;
        }
        
        video {
            width: 100%;
            background-color: #000;
            border: 1px solid #ccc;
        }
        
        .video-label {
            position: absolute;
            top: 10px;
            left: 10px;
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 5px;
            font-size: 14px;
            border-radius: 3px;
        }
        
        .controls {
            text-align: center;
            margin: 20px 0;
        }
        
        button {
            padding: 10px 20px;
            margin: 0 10px;
            font-size: 16px;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
        }
        
        button:hover {
            background-color: #45a049;
        }
        
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        
        #disconnectBtn {
            background-color: #f44336;
        }
        
        #disconnectBtn:hover {
            background-color: #d32f2f;
        }
        
        .status {
            text-align: center;
            margin: 10px 0;
            padding: 10px;
            border-radius: 4px;
            background-color: #e0e0e0;
        }
        
        .connection-status {
            font-weight: bold;
        }
        
        .connected {
            background-color: #c8e6c9;
            color: #388e3c;
        }
        
        .disconnected {
            background-color: #ffcdd2;
            color: #c62828;
        }
        
        .info-panel {
            background-color: #e3f2fd;
            padding: 15px;
            border-radius: 4px;
            margin: 20px 0;
        }
        
        .info-panel h3 {
            margin-top: 0;
        }
        
        .websocket-url {
            width: 100%;
            padding: 8px;
            margin: 10px 0;
            box-sizing: border-box;
        }
    </style>
</head>
<body>
    <h1>WebRTC视频通话</h1>
    
    <div class="info-panel">
        <h3>使用说明</h3>
        <p>1. 打开两个浏览器窗口访问此页面</p>
        <p>2. 在一个窗口中输入WebSocket服务器地址并连接</p>
        <p>3. 在另一个窗口中使用相同的WebSocket地址连接</p>
        <p>4. 其中一个用户点击"开始视频通话"发起通话</p>
        <p>5. 另一个用户点击"接受通话"建立连接</p>
        
        <label for="websocketUrl">WebSocket服务器地址:</label>
        <input type="text" id="websocketUrl" class="websocket-url" 
               value="wss://media.shenglong.com/webrtc" placeholder="例如: wss://media.shenglong.com/webrtc">
    </div>
    
    <div class="controls">
        <button id="connectBtn" onclick="connect()">连接WebSocket</button>
        <button id="disconnectBtn" onclick="disconnect()" disabled>断开连接</button>
        <button id="callBtn" onclick="startCall()" disabled>开始视频通话</button>
        <button id="answerBtn" onclick="answerCall()" disabled>接受通话</button>
        <button id="hangupBtn" onclick="hangup()" disabled>挂断</button>
    </div>
    
    <div id="status" class="status disconnected">未连接</div>
    
    <div class="video-container">
        <div class="video-wrapper">
            <video id="localVideo" autoplay muted playsinline></video>
            <div class="video-label">本地视频</div>
        </div>
        <div class="video-wrapper">
            <video id="remoteVideo" autoplay playsinline></video>
            <div class="video-label">远程视频</div>
        </div>
    </div>

    <script>
        // DOM元素
        const localVideo = document.getElementById('localVideo');
        const remoteVideo = document.getElementById('remoteVideo');
        const statusDiv = document.getElementById('status');
        const connectBtn = document.getElementById('connectBtn');
        const disconnectBtn = document.getElementById('disconnectBtn');
        const callBtn = document.getElementById('callBtn');
        const answerBtn = document.getElementById('answerBtn');
        const hangupBtn = document.getElementById('hangupBtn');
        
        // WebRTC相关变量
        let localStream = null;
        let remoteStream = null;
        let pc = null;
        let websocket = null;
        let isInitiator = false;
        
        // 随机用户ID
        const userId = 'user' + Math.floor(Math.random() * 100000);
        let peerUserId = null;
        
        // ICE服务器配置
        const iceServers = {
            iceServers: [
                { urls: 'stun:stun.l.google.com:19302' },
                { urls: 'stun:global.stun.twilio.com:3478?transport=udp' }
            ]
        };
        
        // 更新连接状态显示
        function updateStatus(message, isConnected = false) {
            statusDiv.textContent = message;
            statusDiv.className = 'status ' + (isConnected ? 'connected' : 'disconnected');
        }
        
        // 连接到WebSocket服务器
        function connect() {
            const websocketUrl = document.getElementById('websocketUrl').value;
            if (!websocketUrl) {
                alert('请输入WebSocket服务器地址');
                return;
            }
            
            try {
                websocket = new WebSocket(websocketUrl);
                setupWebSocket();
            } catch (error) {
                console.error('WebSocket连接失败:', error);
                updateStatus('WebSocket连接失败: ' + error.message);
            }
        }
        
        // 设置WebSocket事件处理
        function setupWebSocket() {
            websocket.onopen = function(event) {
                console.log('WebSocket连接已建立');
                updateStatus('已连接到WebSocket服务器', true);
                connectBtn.disabled = true;
                disconnectBtn.disabled = false;
                callBtn.disabled = false;
            };
            
            websocket.onclose = function(event) {
                console.log('WebSocket连接已断开');
                updateStatus('WebSocket连接已断开');
                connectBtn.disabled = false;
                disconnectBtn.disabled = true;
                callBtn.disabled = true;
                answerBtn.disabled = true;
                hangupBtn.disabled = true;
                stopMediaStream();
            };
            
            websocket.onerror = function(error) {
                console.error('WebSocket错误:', error);
                updateStatus('WebSocket连接错误: ' + error.message);
            };
            
            websocket.onmessage = function(event) {
                const message = JSON.parse(event.data);
                console.log('收到消息:', message);
                
                // 处理不同的消息类型
                switch (message.type) {
                    case 'joined':
                        peerUserId = message.userId;
                        updateStatus(`用户 ${peerUserId} 已加入`, true);
                        break;
                        
                    case 'offer':
                        if (!isInitiator) {
                            handleOffer(message.offer);
                        }
                        break;
                        
                    case 'answer':
                        if (isInitiator) {
                            handleAnswer(message.answer);
                        }
                        break;
                        
                    case 'candidate':
                        handleCandidate(message.candidate);
                        break;
                        
                    case 'hangup':
                        handleHangup();
                        break;
                        
                    case 'ready':
                        answerBtn.disabled = false;
                        break;
                        
                    default:
                        console.warn('未知消息类型:', message.type);
                }
            };
        }
        
        // 断开WebSocket连接
        function disconnect() {
            if (websocket) {
                websocket.close();
                websocket = null;
            }
        }
        
        // 获取本地媒体流
        async function getLocalStream() {
            try {
                const stream = await navigator.mediaDevices.getUserMedia({
                    video: true,
                    audio: true
                });
                localVideo.srcObject = stream;
                localStream = stream;
                return stream;
            } catch (error) {
                console.error('获取本地媒体流失败:', error);
                alert('无法访问摄像头或麦克风: ' + error.message);
                return null;
            }
        }
        
        // 停止媒体流
        function stopMediaStream() {
            if (localStream) {
                localStream.getTracks().forEach(track => track.stop());
                localStream = null;
                localVideo.srcObject = null;
            }
            
            if (remoteStream) {
                remoteStream.getTracks().forEach(track => track.stop());
                remoteStream = null;
                remoteVideo.srcObject = null;
            }
        }
        
        // 创建RTCPeerConnection
        function createPeerConnection() {
            if (pc) {
                pc.close();
            }
            
            pc = new RTCPeerConnection(iceServers);
            
            // 添加本地流到连接
            if (localStream) {
                localStream.getTracks().forEach(track => {
                    pc.addTrack(track, localStream);
                });
            }
            
            // 处理远程流
            pc.ontrack = function(event) {
                console.log('收到远程流');
                remoteVideo.srcObject = event.streams[0];
                remoteStream = event.streams[0];
            };
            
            // 处理ICE候选
            pc.onicecandidate = function(event) {
                if (event.candidate) {
                    console.log('发送ICE候选');
                    websocket.send(JSON.stringify({
                        type: 'candidate',
                        candidate: event.candidate,
                        to: peerUserId
                    }));
                }
            };
            
            // 连接状态变化
            pc.onconnectionstatechange = function() {
                console.log('连接状态变化:', pc.connectionState);
                if (pc.connectionState === 'connected') {
                    updateStatus('通话已建立', true);
                    hangupBtn.disabled = false;
                } else if (pc.connectionState === 'disconnected' || pc.connectionState === 'failed') {
                    updateStatus('连接已断开');
                }
            };
            
            return pc;
        }
        
        // 开始视频通话
        async function startCall() {
            if (!websocket || websocket.readyState !== WebSocket.OPEN) {
                alert('请先连接WebSocket服务器');
                return;
            }
            
            // 获取本地媒体流
            const stream = await getLocalStream();
            if (!stream) return;
            
            // 创建连接
            createPeerConnection();
            
            // 标记为发起方
            isInitiator = true;
            
            // 创建offer
            try {
                const offer = await pc.createOffer();
                await pc.setLocalDescription(offer);
                
                // 发送offer给对方
                websocket.send(JSON.stringify({
                    type: 'offer',
                    offer: offer,
                    to: peerUserId
                }));
                
                updateStatus('正在等待对方接受...');
                callBtn.disabled = true;
            } catch (error) {
                console.error('创建Offer失败:', error);
                alert('创建通话失败: ' + error.message);
            }
        }
        
        // 处理收到的offer
        async function handleOffer(offer) {
            if (!localStream) {
                await getLocalStream();
            }
            
            createPeerConnection();
            
            try {
                await pc.setRemoteDescription(new RTCSessionDescription(offer));
                const answer = await pc.createAnswer();
                await pc.setLocalDescription(answer);
                
                // 发送answer给对方
                websocket.send(JSON.stringify({
                    type: 'answer',
                    answer: answer,
                    to: peerUserId
                }));
                
                updateStatus('通话已建立', true);
                hangupBtn.disabled = false;
                answerBtn.disabled = true;
            } catch (error) {
                console.error('处理Offer失败:', error);
                alert('处理通话请求失败: ' + error.message);
            }
        }
        
        // 处理收到的answer
        async function handleAnswer(answer) {
            try {
                await pc.setRemoteDescription(new RTCSessionDescription(answer));
                updateStatus('通话已建立', true);
                hangupBtn.disabled = false;
            } catch (error) {
                console.error('处理Answer失败:', error);
                alert('建立通话失败: ' + error.message);
            }
        }
        
        // 处理ICE候选
        function handleCandidate(candidate) {
            if (pc) {
                pc.addIceCandidate(new RTCIceCandidate(candidate))
                    .catch(error => {
                        console.error('添加ICE候选失败:', error);
                    });
            }
        }
        
        // 接受通话
        async function answerCall() {
            if (!websocket || websocket.readyState !== WebSocket.OPEN) {
                alert('请先连接WebSocket服务器');
                return;
            }
            
            // 获取本地媒体流
            const stream = await getLocalStream();
            if (!stream) return;
            
            // 发送准备就绪消息
            websocket.send(JSON.stringify({
                type: 'ready',
                to: peerUserId
            }));
            
            answerBtn.disabled = true;
            callBtn.disabled = true;
        }
        
        // 挂断通话
        function hangup() {
            if (pc) {
                pc.close();
                pc = null;
            }
            
            stopMediaStream();
            
            if (websocket && websocket.readyState === WebSocket.OPEN) {
                websocket.send(JSON.stringify({
                    type: 'hangup',
                    to: peerUserId
                }));
            }
            
            updateStatus('通话已结束');
            hangupBtn.disabled = true;
            callBtn.disabled = false;
            answerBtn.disabled = true;
            isInitiator = false;
            peerUserId = null;
        }
        
        // 处理对方挂断
        function handleHangup() {
            if (pc) {
                pc.close();
                pc = null;
            }
            
            stopMediaStream();
            
            updateStatus('对方已挂断');
            hangupBtn.disabled = true;
            callBtn.disabled = false;
            answerBtn.disabled = true;
            isInitiator = false;
            peerUserId = null;
        }
        
        // 页面卸载时清理资源
        window.addEventListener('beforeunload', function() {
            hangup();
            disconnect();
        });
    </script>
</body>
</html>